home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / TravelingSalesman / Source_code / PlotView.m < prev    next >
Encoding:
Text File  |  1992-08-18  |  20.0 KB  |  770 lines

  1. /* 
  2.  * PlotView.m -- Implementation file for the PlotView class 
  3.  *
  4.  * You may freely copy, distribute, and reuse the code in this example.
  5.  * NeXT disclaims any warranty of any kind, expressed or implied, as to its
  6.  * fitness for any particular use.
  7.  *
  8.  * This is an implementation of the PlotView class to demonstrate the effects 
  9.  * and use of simulated annealing, in particular the Traveling Salesman Problem
  10.  * (TSP). Implemented by Nolan R. Davis and Joseph Jeffery in the Acoustics 
  11.  * Division of the Naval Research Laboratory.
  12.  */
  13.  
  14. #import "PlotView.h"
  15. #import "drawingFuncs.h"
  16. #import <objc/Storage.h>
  17. #import <appkit/NXCursor.h>
  18. #import <appkit/Application.h>
  19. #import <appkit/Window.h>
  20. #import <appkit/FormCell.h>
  21. #import <appkit/Control.h>
  22. #import <appkit/Pasteboard.h>
  23. #import <NXCType.h> 
  24. #import <math.h> 
  25. #import <dpsclient/psops.h>
  26. #import <dpsclient/wraps.h>
  27. #import <stdlib.h> 
  28. #import <string.h> 
  29. #define MAXNUMLENGTH 50
  30. #define DEFAULTRADIUS 4.0
  31. int route = 0;
  32. float mu = 1.0;
  33.   long        ialpha;
  34.   long        ibeta;
  35.   long        ir;
  36. int ttt=0;
  37. /* Subroutines used in the annealing, found at the end. */
  38. extern double get_distance( int k , int l );
  39. extern double min_value ( double a, double b );
  40. extern double get_uniform_random( );
  41. extern float getNumber(NXStream *stream);
  42. extern int getSeparator(NXStream *stream);
  43.  
  44. /* Structures used to store the coordinates of the cities and the paths between them. */
  45.   struct     {
  46.     double    x;
  47.     double    y;
  48. }city[30];
  49.  
  50.  struct    {
  51.     int     city;
  52.     double    length;
  53. }path[30],bestpath[30];
  54.  
  55.  
  56. @implementation PlotView
  57.  
  58. - initFrame:(const NXRect *)frameRect
  59.  
  60. /* Initializes the new PlotView object. First, an initFrame: message is sent to  super to initialize PlotView as a View.  Next, the PlotView sets its own state -- that it is opaque and that the origin of its coordinate system lies in  the center of its area. It then creates and initializes its associated objects, a Storage object, an NXCursor, and a Cell.  Finally, it loads into the Window Server some PostScript procedures that it will use in drawing itself. 
  61.  */
  62.  
  63. {
  64.     NXPoint    spot;
  65.     
  66.     [super initFrame:frameRect];
  67.     [self setOpaque:YES];
  68.     [self setRadius:DEFAULTRADIUS];
  69.     [self translate:floor(frame.size.width/2) :floor(frame.size.height/2)];
  70.     [self scale:1 :1];
  71.  
  72.  
  73.  
  74.     points = [[Storage alloc] initCount:0 elementSize:sizeof(NXPoint) description:"{ff}"];
  75.     crossCursor = [NXCursor newFromImage:[NXImage newFromSection:"cross.tiff"]];
  76.     spot.x = spot.y = 7.0;
  77.     [crossCursor setHotSpot:&spot];
  78.     /* 
  79.      * Normally, the next two message expressions would be combined, as:
  80.      *         readOut = [[Cell alloc] initTextCell:""];
  81.      * but are here separated for clarity.
  82.      */
  83.     /*readOut = [[FormCell alloc] initTextCell:""];*/
  84.     loadPSProcedures();
  85.     return self;
  86. }
  87.  
  88. - setTextCell:aTextField
  89. {
  90. readOut=aTextField;    
  91.  
  92. return self;
  93. }
  94. - setDelegate:anObject
  95. /*
  96.  * Sets the PlotView's delegate instance variable to the supplied object.
  97.  */
  98. {
  99.     delegate = anObject;
  100.     return self;
  101. }
  102.  
  103.  
  104. - drawSelf:(const NXRect *)rects :(int)rectCount
  105. /*
  106.  * Draws the PlotView's background and axes.  If there are any points,
  107.  * these are drawn too.
  108.  *
  109.  * (Note:  For simplicity, although PlotView only repaints the background 
  110.  * of the update region, it redraws the entire axes.  For better performance, 
  111.  * only those parts of the axes that fall within the update region should 
  112.  * be redrawn.)   
  113.  */
  114. {
  115.     unsigned int     i,j;
  116.     NXPoint        *aPoint, *bPoint;
  117.     int c;
  118.     if (rects == NULL) return self;
  119.  
  120.     /* If we're printing, we need to load drawing procedures to the printing context.  This simple test is OK for a View that prints a single page.  If there were multiple pages, the procedures would be loaded multiple times.  Although this is inefficient, it causes no error.  Views that print multiple pages should load procedures such as these in an endPrologue method (see the View spec sheet). */
  121.  
  122.     if (NXDrawingStatus != NX_DRAWING) 
  123.         loadPSProcedures();
  124.  
  125.     /* paint visible area white then draw axes */
  126.     PSsetgray(NX_WHITE);
  127.     NXRectFill(&rects[0]);
  128.     PSsetgray(NX_DKGRAY);
  129.     drawAxes(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
  130.         c=0;
  131.     
  132.     /* now take each point and draw it */
  133.     PSsetgray(NX_BLACK);
  134.     i = [points count];
  135.        j=i;
  136.     while (i--) {
  137.         aPoint = (NXPoint *)[points elementAt:i];
  138.         drawCircle(aPoint->x, aPoint->y, radius);
  139.         
  140.     /* Now draw the connecting lines */    
  141.         if(route==1){
  142.           if(c==1){
  143.             bPoint = (NXPoint *)[points elementAt:i+1];
  144.             join(aPoint->x, aPoint->y,bPoint->x, bPoint->y);}
  145.             else{bPoint = (NXPoint *)[points elementAt:0];join(aPoint->x, aPoint->y,bPoint->x, bPoint->y);}c=1;}
  146.         } 
  147.      
  148.     return self;
  149. }
  150.  
  151. - DoRoute:sender
  152. {
  153. /* Called when the Find & Show Route button is pressed. It does the main part of the annealing  and then calls plot self to display it*/
  154.   unsigned      int     i;
  155.   NXPoint        *aPoint, bPoint;
  156.   int           NCITY,itmp,n_iterations,n_no_change,change,z,k3,trials;
  157.   static    int    j;
  158.   static    int    k1;
  159.   static    int    k2;
  160.   static    double    e;
  161.   static    double    delta_e;
  162.   static    double    best_e;
  163.   static    double    temperature;
  164.   static    double    e_baseline;
  165.   static    double    r;
  166.   static    double     trial_length_1_in;
  167.   static    double     trial_length_1_out;
  168.   static    double     trial_length_2_in;
  169.   static    double     trial_length_2_out;
  170.   static    double     length_1_in;
  171.   static    double     length_2_out;
  172.   static    double     length_2_in;
  173.   static    double     length_1_out;
  174.   ialpha = pow(7,5);
  175.   ibeta = pow(2,13) - 1;
  176.   ir = 111;
  177. route=1;
  178.  
  179. /* Read in the values from the window */
  180. [initTemp takeIntValueFrom:initTemp];
  181. temperature =[initTemp intValue];
  182. [Iterations takeIntValueFrom:Iterations];
  183. trials =[Iterations intValue]+1;
  184. n_iterations = 2;
  185. [freeze takeIntValueFrom:freeze];
  186. change = [freeze intValue];
  187.  
  188. n_no_change =0;
  189. i = [points count];
  190. NCITY = i;
  191. e=0;
  192. z=0;
  193. ttt=1;
  194. while (i--) {aPoint = (NXPoint *)[points elementAt:i];
  195.      city[i].x=aPoint->x;city[i].y=aPoint->y;
  196. }
  197.  
  198. for ( j=0; j < NCITY; j++) {
  199.      path[j].city = j ;
  200.      k1 = path[j].city;
  201.      path[j].length = get_distance( j, (j+1)%NCITY );
  202.      e += path[j].length;
  203.      bestpath[j].city= path[j].city;
  204.   } 
  205. best_e=e;e_baseline=e;
  206. while (n_no_change < change) {
  207.  
  208.   n_iterations++;
  209.     
  210.   for ( k1 = 0; k1 < NCITY; k1++ ) {
  211.     
  212.       do {
  213.          r = get_uniform_random();
  214.          k2 = floor( NCITY * r );
  215.       }
  216.       while (k1==k2);    z++;           
  217.       
  218.       /* Plots out intermediate steps of the annealing if requested. */
  219.       
  220.       if (trials>0){
  221.          if(z%trials==0){ for ( j=0; j <= NCITY-1; j++) {
  222.             k3 = bestpath[j].city;
  223.             bPoint.x =city[k3].x;
  224.             bPoint.y =city[k3].y;
  225.             [points replace:&bPoint at:j];
  226.          }    
  227.         [delegate NukeCities:self];
  228.         for(j=0;j<=NCITY-1;j++) {
  229.             if (delegate && [delegate respondsTo:@selector(plotView:pointDidChange:)])
  230.             [delegate plotView:self pointDidChange:[points elementAt:j]];
  231.             }
  232.         [self plot:self];}
  233.      }
  234.  
  235.  /* The possible new path lengths */
  236.  
  237.       trial_length_2_in = get_distance ( path[k2].city, path[ (k1-1+NCITY)%NCITY ].city );
  238.       trial_length_1_out = get_distance ( path[k1].city, path[ (k2+1)%NCITY ].city );
  239.       trial_length_2_out = get_distance ( path[k2].city, path[ (k1+1+NCITY)%NCITY ].city );
  240.       trial_length_1_in = get_distance ( path[k1].city, path[ (k2-1+NCITY)%NCITY ].city );
  241.    
  242.    /* The old path lengths*/
  243.    
  244.       length_1_out = get_distance ( path[k1].city, path[ (k1-1+NCITY)%NCITY ].city );
  245.       length_1_in = get_distance ( path[k1].city, path[ (k1+1)%NCITY ].city );
  246.       length_2_out = get_distance ( path[k2].city, path[ (k2-1+NCITY)%NCITY ].city );
  247.       length_2_in = get_distance ( path[k2].city, path[ (k2+1)%NCITY ].city );
  248.  
  249.        /* Compute energy change */
  250. /* The case where k2 differs from k1 by 1 requires special handling.  */
  251. /* The case where k2 differs from k1 by 2 is more efficient with special handling. */
  252. /* Also, this particular representation depends on which of k1 and k2 is greater.   */
  253.  
  254.       if ( k2 == (k1+1)%NCITY ) {
  255.               delta_e = trial_length_1_out + trial_length_2_in
  256.                                     - length_1_out - length_2_in;
  257.              if ( get_uniform_random() < exp(-delta_e/temperature) ) {
  258.  
  259.          /* The state is accepted. Interchange intermediate cities */
  260.  
  261.         e += delta_e;
  262.         itmp = path[k1].city;
  263.     path[k1].city = path[k2].city;
  264.     path[k2].city = itmp;
  265.     
  266.     if(best_e>e){for ( j=0; j <= NCITY-1; j++) {
  267.         bestpath[j].city= path[j].city;}best_e=e;}
  268. }
  269. }
  270.       else if (k2 == (k1-1+NCITY)%NCITY  )  {
  271.                delta_e = trial_length_1_in + trial_length_2_out
  272.                                     - length_1_in - length_2_out;
  273.                 if ( get_uniform_random() < exp(-delta_e/temperature) ) {
  274.  
  275.          /* The state is accepted. Interchange intermediate cities */
  276.  
  277.         e += delta_e;
  278.         itmp = path[k1].city;
  279.     path[k1].city = path[k2].city;
  280.     path[k2].city = itmp;
  281.  
  282.     if(best_e>e){for ( j=0; j <= NCITY-1; j++) {
  283.         bestpath[j].city= path[j].city;}best_e=e;}
  284. }
  285. }
  286.            else {
  287.               delta_e = trial_length_1_in + trial_length_1_out + trial_length_2_in + trial_length_2_out
  288.                     - length_1_in - length_1_out- length_2_in - length_2_out;
  289.                 if ( get_uniform_random() < exp(-delta_e/temperature) ) {
  290.  
  291.          /* The state is accepted. Interchange intermediate cities */
  292.  
  293.         e += delta_e;
  294.     
  295.         itmp = path[k1].city;
  296.     path[k1].city = path[k2].city;
  297.     path[k2].city = itmp;
  298.         
  299. if(best_e>e){for ( j=0; j <= NCITY-1; j++) {
  300.         bestpath[j].city= path[j].city;}best_e=e;}
  301.     
  302.  
  303. }
  304. }
  305.  
  306.  
  307.   }    
  308.     /* Have finished one loop through the cities.    */
  309.     /* Now reduce the temperature.            */
  310.  
  311.  
  312.     temperature *= min_value( ( (float) n_iterations ) /  ( (float) (n_iterations+1) ) , 
  313.                      2./(1.+exp(mu*(e_baseline/e - 1.) ) ) );
  314.  
  315.  
  316. [temp setIntValue:temperature];
  317.  
  318.     if (e < e_baseline) {
  319.       e_baseline = e;
  320.       n_no_change = 0;
  321. [pathL setIntValue:e_baseline];
  322.  
  323.  
  324.     }
  325.     else n_no_change++;
  326.  
  327.   }
  328.   /* End of while loop.    */
  329.  
  330.  
  331.  
  332.   /* At this point the system is frozen.  Plot results (best path not final path).*/
  333. printf("Z=%d",z);
  334.   printf( "   Final energy:  %8f\n",best_e);
  335.   for ( j=0; j <= NCITY-1; j++) {
  336.     k3 = bestpath[j].city;
  337.     printf  ( "Final:    %8f %8f\n", city[k3].x, city[k3].y);
  338.     bPoint.x =city[k3].x;
  339.  bPoint.y =city[k3].y;
  340.  [points replace:&bPoint at:j];
  341.  
  342.   }    
  343. [delegate NukeCities:self];
  344.  for(j=0;j<=NCITY-1;j++) {
  345.         if (delegate && [delegate respondsTo:@selector(plotView:pointDidChange:)])
  346.                     [delegate plotView:self pointDidChange:[points elementAt:j]];
  347.         }
  348. [self plot:self];
  349. route=0;
  350. ttt=0;
  351. return self;
  352. }
  353.  
  354.  
  355. - clear:sender
  356. /*
  357.  * Clears the PlotView by emptying its Storage object of all points
  358.  * and then redisplaying the PlotView.  This action is taken only if
  359.  * the PlotView's state requires it.
  360.  */
  361. {
  362.     if (needsClearing) {
  363.         [points empty];
  364.         [self display];
  365.         needsClearing = NO;
  366.     }
  367.     return self;
  368. }
  369.  
  370. - sizeTo:(NXCoord)width :(NXCoord)height
  371. /*
  372.  * Ensures that whenever the PlotView is resized, the origin of its 
  373.  * coordinate system is repositioned to the center of its area.
  374.  */
  375. {
  376.     [super sizeTo:width :height];
  377.     [self setDrawOrigin:-floor(width/2) : -floor(height/2)]; 
  378.     return self;
  379. }
  380.  
  381. - registerPoint:(NXPoint *)aPoint
  382. /*
  383.  * Adds a point to the list the PlotView keeps in its Storage object. 
  384.  */
  385. {
  386.     [points addElement:aPoint];
  387.     return self;
  388. }
  389.  
  390. - mouseDown:(NXEvent *) theEvent
  391. /*
  392.  * Responds to a message the system sends whenever the user presses the mouse
  393.  * button when the cursor is over the PlotView.  The PlotView changes the 
  394.  * cursor to a cross-hairs image and then starts asking for mouse-dragged or mouse-
  395.  * up events.  As it receives mouse-dragged events, the PlotView updates the readOut
  396.  * text Cell with the cursor's coordinates.  If the user releases the mouse
  397.  * button while the cursor is over the PlotView, the PlotView registers the 
  398.  * point and then sends a message to its delegate notifying it of the new 
  399.  * point. If there is a city at the location of the mouseDown its value is 
  400.  * eliminated from the list while the new mouse dragged location is put in its
  401.  * place. Effectually grabbing and moving the point to a new location.
  402.  * 
  403.  */
  404. {
  405.     int    looping = YES, oldMask,distsq,i,X,Y,X1,Y1,z,j;
  406.     NXPoint    aPoint,*cPoint,*bPoint;
  407.     NXRect    plotRect, cellRect;
  408.        char    buffer[100];
  409.  
  410.  
  411.  [crossCursor set];
  412.  [self getBounds:&plotRect];
  413.  NXSetRect(&cellRect, plotRect.origin.x, plotRect.origin.y, 100.0, 20.0);
  414.  oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK];
  415.  [self lockFocus];
  416.  aPoint = theEvent->location;
  417.  [self convertPoint:&aPoint fromView:nil];
  418.  distsq=0;
  419.  z=1;
  420.  i = [points count];
  421.  
  422.  /* See if the new mouse down is at the same location as an old city. */
  423.  
  424.  while (i--) {
  425.     if(z==1){bPoint = (NXPoint *)[points elementAt:i];
  426.          X=bPoint->x;Y=bPoint->y;
  427.          cPoint = &aPoint;
  428.          X1=cPoint->x;Y1=cPoint->y;
  429.          distsq = (X-X1)*(X-X1)+(Y-Y1)*(Y-Y1);
  430.          if(distsq<11){z=0;j=i;}}
  431.  }
  432.  if(z==0){
  433.  
  434.  /* The mouse was over another city, eliminate it and show new city. */
  435.  
  436.     do {
  437.        aPoint = theEvent->location;
  438.        [self convertPoint:&aPoint fromView:nil];
  439.        sprintf(buffer, "(%d,%d)->(%d, %d)", X,Y,(int)aPoint.x, (int)aPoint.y); 
  440.          [readOut setStringValue:buffer];
  441.         [window flushWindow];
  442.        if (theEvent->type == NX_MOUSEUP) {
  443.               /*  on mouse-up, register point, inform delegate, and clean up state */
  444.         [readOut setStringValue:""];
  445.               /*[readOut drawInside:&cellRect inView:self];*/
  446.         [window flushWindow];
  447.         if (NXPointInRect(&aPoint, &plotRect)) {
  448.             PSsetgray(NX_BLACK);
  449.             drawCircle(aPoint.x, aPoint.y, radius);
  450.             [window flushWindow];
  451.             bPoint = &aPoint;
  452.             [points replace:&aPoint at:j];
  453.             [self display];
  454.                         [delegate NukeCities:self];
  455.                     i = [points count];
  456.                     for(j=0;j<=i-1;j++) {
  457.  
  458.                              if (delegate && [delegate respondsTo:@selector(plotView:pointDidChange:)])
  459.                             [delegate plotView:self pointDidChange:[points elementAt:j]];
  460.                         }
  461.             needsClearing = YES;
  462.         }
  463.         looping = NO;
  464.           }    
  465.        }while(looping &&(theEvent=[NXApp getNextEvent:NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK]));
  466.     [self unlockFocus];
  467.     [window setEventMask:oldMask];
  468.     [NXArrow set];
  469.     return self;
  470. }
  471. else{
  472.  
  473. /* The mouse was not over another city: treat normally and add the new city to the map and memory. */
  474.  
  475.     do {
  476.         aPoint = theEvent->location;
  477.         [self convertPoint:&aPoint fromView:nil];
  478.         sprintf(buffer, "(%d, %d)", (int)aPoint.x, (int)aPoint.y); 
  479.           [readOut setStringValue:buffer];
  480.           /*[readOut drawInside:&cellRect inView:self];*/
  481.         [window flushWindow];
  482.         if (theEvent->type == NX_MOUSEUP) {
  483.         /* on mouse-up, register point, inform delegate, and clean up state */
  484.             [readOut setStringValue:""];
  485.               /*[readOut drawInside:&cellRect inView:self];*/
  486.             [window flushWindow];
  487.             if (NXPointInRect(&aPoint, &plotRect)) {
  488.                 PSsetgray(NX_BLACK);
  489.                 drawCircle(aPoint.x, aPoint.y, radius);
  490.                 [window flushWindow];
  491.                 [self registerPoint:&aPoint];
  492.                 needsClearing = YES;
  493.                 if (delegate && [delegate respondsTo:@selector(plotView:pointDidChange:)])
  494.                     [delegate plotView:self pointDidChange:&aPoint];
  495.             }
  496.             looping = NO;
  497.         }    
  498.        } while(looping &&(theEvent=[NXApp getNextEvent:NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK]));
  499.     [self unlockFocus];
  500.     [window setEventMask:oldMask];
  501.     [NXArrow set];
  502.     return self;
  503. }}
  504.  
  505. - Nuke:sender
  506. {
  507.  
  508. /* Clears all memory of cities, clears the map and the list.*/
  509.  
  510.   [delegate NukeCities:sender];
  511.   [self clear:self];
  512.   return self;
  513. }
  514.  
  515. - setRadius:(float)aFloat
  516. /*
  517.  * Sets the value for the radius of the PlotView's points.
  518.  */
  519. {
  520.     radius = aFloat;
  521.     return self;
  522. }
  523.  
  524. - setXmax:anObject
  525. {
  526.     xmax = anObject;
  527.     return self;
  528. }
  529. - setXmin:anObject
  530. {
  531.     xmin = anObject;
  532.     return self;
  533. }
  534. - setYmax:anObject
  535. {
  536.     ymax = anObject;
  537.     return self;
  538. }
  539. - setYmin:anObject
  540. {
  541.     ymin = anObject;
  542.     return self;
  543. }
  544. - setFreeze:anObject
  545. {
  546.     freeze = anObject;
  547.     return self;
  548. }
  549. - setInitTemp:anObject
  550. {
  551.     initTemp = anObject;
  552.     return self;
  553. }
  554. - setPathL:anObject
  555. {
  556.     pathL = anObject;
  557.     return self;
  558. }
  559. - setTemp:anObject
  560. {
  561.     temp = anObject;
  562.     return self;
  563. }
  564.  
  565.  
  566. - (float)radius
  567. /*
  568.  * Returns the value for the radius of the PlotView's points.
  569.  */
  570. {
  571.     return radius;
  572. }
  573.  
  574.  
  575. - read:(NXTypedStream *)stream
  576. /*
  577.  * Unarchives the PlotView.  Initializes four of the PlotView's instance variables
  578.  * to the values stored in the stream. 
  579.  */
  580. {
  581.     [super read:stream];
  582.     delegate = NXReadObject(stream);
  583.     NXReadTypes(stream, "@@@f", &points, &crossCursor, &readOut, &radius);
  584.     return self;
  585. }
  586.  
  587. - write:(NXTypedStream *)stream
  588. /*
  589.  * Archives the PlotView by writing its important instance variables to the stream. 
  590.  */
  591. {
  592.     [super write:stream];
  593.     NXWriteObjectReference(stream, delegate);
  594.     NXWriteTypes(stream, "@@@f", &points, &crossCursor, &readOut, &radius);
  595.     return self;
  596. }
  597.  
  598. - awake
  599. /*
  600.  * Finishes initializing a PlotView that has just been unarchived (see the read: method).
  601.  */
  602. {
  603.     loadPSProcedures();
  604.     return [super awake];
  605. }
  606.  
  607.  
  608. - (const char *)inspectorName
  609. {
  610.     return "PlotViewInspector";
  611. }
  612.  
  613. - CoolingOff:sender
  614. {
  615. mu =1.0;
  616. return self;
  617. }
  618. - CoolingOn:sender
  619. {
  620. mu =0.0;
  621. return self;
  622. }
  623.  
  624.  
  625. - plot:sender
  626. /*
  627.  * Responds to a plot: message by asking the PlotView's delegate for a stream
  628.  * containing the points to plot.  It then extracts number pairs from the stream
  629.  * and creates NXPoint structures with them.  For each structure it creates, the 
  630.  * PlotView sends itself a registerPoint: message to add the point to its list of 
  631.  * points.  This simple parser ignores input it doesn't understand.
  632.  */
  633. {
  634.     int          i,NCITY,c, sign, retval ,pathlength;
  635.     float          aNum;
  636.     NXPoint          aPoint;
  637.       NXPoint        *bPoint;
  638.     NXStream    *stream;
  639.     BOOL         processedLine = NO, gotFirst = NO, gotSecond = NO;
  640.     route=1;
  641.         [self clear:self];
  642.     if (delegate && [delegate respondsTo:@selector(plotView:providePoints:)])
  643.         [delegate plotView:self providePoints:&stream];
  644.     NXSeek(stream, 0, NX_FROMSTART);
  645.     while ((c = NXGetc(stream)) != EOF){
  646.         sign = 1;
  647.         retval = getSeparator(stream);
  648.         if (retval == 1) {
  649.             c = NXGetc(stream);
  650.         } else if (retval == -1) {
  651.             break;
  652.         }
  653.         if (!NXIsDigit(c)) {
  654.             if ((c == '-') && NXIsDigit(c = NXGetc(stream))){
  655.                     sign = -1;
  656.             } else {
  657.                 while( (c != '\n') && (c != EOF)) {
  658.                     c = NXGetc(stream);
  659.                     processedLine = YES;
  660.                 }
  661.             }
  662.         }
  663.         if (c == EOF)
  664.             break;
  665.         else if (processedLine) {
  666.             processedLine = NO;
  667.             continue;
  668.         }
  669.         aNum = getNumber(stream);
  670.         if (!gotFirst) {
  671.             aPoint.x = sign * aNum;
  672.             gotFirst = YES;
  673.         } else if (!gotSecond) {
  674.             aPoint.y = sign * aNum;
  675.             [self registerPoint:&aPoint];
  676.             gotFirst = gotSecond = NO;
  677.         } 
  678.     }
  679.     if(ttt==0){
  680.         i = [points count];
  681.     NCITY = i;
  682.  
  683.     while (i--) {bPoint = (NXPoint *)[points elementAt:i];
  684.          city[i].x=bPoint->x;city[i].y=bPoint->y;
  685.     }
  686. pathlength=0;
  687. for ( i=0; i < NCITY; i++) {
  688.      pathlength =pathlength+ get_distance( i, (i+1)%NCITY );
  689.   } 
  690. [pathL setIntValue:pathlength];
  691. pathlength = pathlength*5;
  692.   [initTemp setIntValue:pathlength];
  693.   [freeze setIntValue:NCITY*10];}ttt=1;
  694.     [self display];
  695.     needsClearing = YES;
  696.     return self;
  697. }
  698.  
  699. int getSeparator(NXStream *stream)
  700. /* 
  701.  * Removes white space, commas, and plus signs from between 
  702.  * number pairs.
  703.  */
  704. {
  705.     int c, firstChar;
  706.     
  707.     NXUngetc(stream);
  708.     c = firstChar = NXGetc(stream);
  709.     while (NXIsSpace(c) || (c == ',') || (c == '+'))
  710.         c = NXGetc(stream);
  711.     /* 1 = ate something; 0 = ate nothing; -1 means EOF */
  712.     if (c == firstChar)
  713.         return 0;
  714.     else if (c == EOF)
  715.         return -1;
  716.     NXUngetc(stream);
  717.     return 1;
  718. }
  719.  
  720. float getNumber(NXStream *stream)
  721. /* 
  722.  * Composes a floating point number from a string of number  
  723.  * characters.
  724.  */
  725. {
  726.     int c, i = 0;
  727.     char temp[MAXNUMLENGTH];
  728.     
  729.     NXUngetc(stream);
  730.     c = NXGetc(stream);
  731.     while ((NXIsDigit(c) || (c == '.')) && (c != '\n') && (c != EOF)) {
  732.         temp[i++] = c;
  733.         c = NXGetc(stream);
  734.     }
  735.     NXUngetc(stream);
  736.     temp[i] = 0;
  737.     return (atof(temp));
  738. }
  739.  
  740.  
  741. static double get_distance( int k , int l )
  742. {    
  743.   static double distance;
  744.  
  745.   distance = sqrt( ( city[k].x - city[l].x ) * ( city[k].x - city[l].x )
  746.             + ( city[k].y - city[l].y ) * ( city[k].y - city[l].y ) );
  747.             
  748.   return distance;
  749. }
  750.  
  751.  
  752. static double get_uniform_random( )
  753. {
  754.   static double r;
  755.     
  756.   ir = (ialpha*ir) % ibeta;
  757.     
  758.   r = ( (double) ir ) / ( (double) ibeta );
  759.   return r;
  760. }
  761.  
  762.  
  763. static double min_value ( double a, double b )
  764. {
  765.   if ( a < b ) return a;
  766.   else return b;
  767. }
  768.  
  769.  
  770. @end